package net.sf.odinms.exttools.doclet.pages;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.tools.doclets.internal.toolkit.util.ClassDocCatalog;
import com.sun.tools.doclets.internal.toolkit.util.DirectoryManager;
import com.sun.tools.doclets.internal.toolkit.util.Util;
import net.sf.odinms.exttools.doclet.AbstractPageWriter;
import net.sf.odinms.exttools.doclet.Doclet;

/**
 * Creates "{packagepath}/package-frame.html" which lists a package's members.
 * Package members (classes, interfaces, enums, etc.) are alphabetized and
 * grouped . These files substitute for "allclasses-frame.html" in the lower
 * left when the corresponding package is selected in the upper-left frame.
 */
public final class PackageFrame extends AbstractPageWriter {
	
	/**
	 * The classes to be documented. (Use this to filter out other classes.)
	 */
	private Set<ClassDoc> documentedClasses;
	
	/**
	 * Generate a listing of all package members for use in lower-left frame.
	 * 
	 * @param pkg The package for which to create the member listing.
	 */
	// TODO Refactor the existing Package Frame generation into XHTML
	public static void generatePackageFrame(PackageDoc pkg) {
		String filename = "package-frame" + CONF.ext;
		String pathToFile = DirectoryManager.getDirectoryPath(pkg);
		try {
			new PackageFrame(pkg, filename, pathToFile);
		}
		catch (IOException exc) {
			throw Doclet.exception(exc, pathToFile + SLASH + filename);
		}
	}
	
	/**
	 * Initalize filename and set of classes to document for a package frame.
	 * 
	 * @param pkg The {@link PackageDoc package} to create a frame for.
	 * @param filename The desired name of the file (with extension).
	 * @param pathToFile The path from the document root to this file.
	 * @throws IOException If {@link java.io.FileOutputStream} creation fails.
	 */
	private PackageFrame(PackageDoc pkg, String filename, String pathToFile)
			throws IOException {
		super(filename, pathToFile);
		pageType = PageType.PACKAGE_FRAME;
		
		if (CONF.root.specifiedPackages().length == 0) {
			documentedClasses =
					new HashSet<ClassDoc>(Arrays.asList(CONF.root.classes()));
		}
		String pkgName = Util.getPackageName(pkg);
		String[] metaKeywords = {pkgName + " " + "package"};
		windowTitle = CONF.propertyText("Package") + " " + pkgName;
		
		printXhtmlHeader(metaKeywords, false);
		
		println(open("h3")
				+ linkToLabelHrefTarget(pkgName, pathToPackageFile(pkg,
						"package-summary" + CONF.ext), "classFrame")
				+ close("h3"));
		// Generate class listings, with separate listings by class type
		if (pkg.isIncluded()) {
			printClassListing(pkg.interfaces(), "Interfaces");
			printClassListing(pkg.ordinaryClasses(), "Classes");
			printClassListing(pkg.enums(), "Enums");
			printClassListing(pkg.exceptions(), "Exceptions");
			printClassListing(pkg.errors(), "Errors");
			printClassListing(pkg.annotationTypes(), "Annotation_Types");
		} else {
			String name = Util.getPackageName(pkg);
			ClassDocCatalog classes = CONF.classDocCatalog;
			printClassListing(classes.interfaces(name), "Interfaces");
			printClassListing(classes.ordinaryClasses(name), "Classes");
			printClassListing(classes.enums(name), "Enums");
			printClassListing(classes.exceptions(name), "Exceptions");
			printClassListing(classes.errors(name), "Errors");
			printClassListing(classes.annotationTypes(name), "Annotation_Types");
		}
		
		printXhtmlFooter();
		this.close();
	}
	
	/**
	 * Generate specific class kind listing. Also add label to the listing.
	 * 
	 * @param classes Array of specific class kinds, namely: Class, Interface,
	 *        Exception, or Error.
	 * @param labelProperty Label for the listing.
	 */
	private void printClassListing(ClassDoc[] classes, String labelProperty) {
		String label = CONF.propertyText(labelProperty);
		if (classes.length > 0) {
			Arrays.sort(classes);
			
			println(openDivWithID(label));
			println(new TagBuilder("h4").getOpenTextClose(label));
			
			for (ClassDoc cur : classes) {
				if (documentedClasses != null
						&& !documentedClasses.contains(cur)) {
					continue;
				}
				if (!Util.isCoreClass(cur) || !CONF.isGeneratedDoc(cur)) {
					continue;
				}
				// Since this is for a single package and organized by type,
				// it really seems like a waste to print all the link titles.
				// String title =
				// CONF.propertyText(getLinkPropertyForProperty(labelProperty),
				// cur.containingPackage().name()));
				println(linkToLabelHrefTarget(cur.name(),
						cur.name() + CONF.ext, "classFrame")
						+ empty("br"));
			}
			
			println(close("div") + getComment(label));
		}
	}
	
	/*
	 * private String getLinkPropertyForProperty(String entityType) {
	 * System.out.println(entityType); String linkTitle = ""; if
	 * (entityType.equals("doclet.Interfaces")) linkTitle =
	 * "doclet.hrefTitleInterface"; else if
	 * (entityType.equals("doclet.Classes")) linkTitle =
	 * "doclet.hrefTitleClass"; else if (entityType.equals("doclet.Enums"))
	 * linkTitle = "doclet.hrefTitleEnum"; else if
	 * (entityType.equals("doclet.Exceptions")) linkTitle =
	 * "doclet.hrefTitleException"; else if (entityType.equals("doclet.Errors"))
	 * linkTitle = "doclet.hrefTitleError"; else if
	 * (entityType.equals("doclet.AnnotationTypes")) linkTitle =
	 * "doclet.hrefTitleAnnotation"; return linkTitle; }
	 */
}
